﻿#ifndef QBASEENTITY_H
#define QBASEENTITY_H
/***************************************
 * 【文件说明】： QT程序实体类基类 (BaseEntity)
 * 【使用方法】：
//1. 继承基类写一个人对象类
#include "person.h"

Person::Person(QObject *parent)
    : QBaseEntity(parent)
{
}

int Person::id() const
{
    return m_id;
}

void Person::setId(int id)
{
    m_id = id;
}

QString Person::name() const
{
    return m_name;
}

void Person::setName(const QString &name)
{
    m_name = name;
}

int Person::age() const
{
    return m_age;
}

void Person::setAge(int age)
{
    m_age = age;
}

double Person::height() const
{
    return m_height;
}

void Person::setHeight(double height)
{
    m_height = height;
}

bool Person::isStudent() const
{
    return m_isStudent;
}

void Person::setIsStudent(bool isStudent)
{
    m_isStudent = isStudent;
}

QList<int> Person::grades() const
{
    return m_grades;
}

void Person::setGrades(const QList<int> &grades)
{
    m_grades = grades;
}

//2. 使用人对象类
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 Person 实例
    Person person;
    person.setId(1);
    person.setName("John Doe");
    person.setAge(30);
    person.setHeight(175.5);
    person.setIsStudent(true);
    person.setGrades({90, 85, 95, 88});

    // 将 Person 实例转换为 JSON
    QJsonObject jsonObject = person.toJson();
    QJsonDocument jsonDoc(jsonObject);
    QString jsonString = jsonDoc.toJson(QJsonDocument::Indented);

    // 输出 JSON 字符串
    QTextStream out(stdout);
    out << "Person to JSON:\n" << jsonString << "\n";

    // 从 JSON 字符串反序列化到 Person 实例
    QJsonDocument parsedJson = QJsonDocument::fromJson(jsonString.toUtf8());
    if (parsedJson.isObject()) {
        person.fromJson(parsedJson.object());

        // 输出反序列化后的 Person 属性
        out << "Parsed Person:\n";
        out << "ID: " << person.id() << "\n";
        out << "Name: " << person.name() << "\n";
        out << "Age: " << person.age() << "\n";
        out << "Height: " << person.height() << "\n";
        out << "Is Student: " << (person.isStudent() ? "Yes" : "No") << "\n";
        out << "Grades: ";
        for (int grade : person.grades()) {
            out << grade << " ";
        }
        out << "\n";
    }

    return a.exec();
}
***************************************/

#include <QObject>
#include <QMetaProperty>
#include <QJsonObject>
#include <QJsonArray>
#include <QSqlQuery>
#include <QDateTime>

/**
 * @brief QBaseEntity 是一个基于 QObject 的基类，用于支持将对象属性序列化为 JSON 格式以及从 JSON 格式反序列化。
 *
 * 该类提供了一个基础框架，使得子类可以轻松地实现 toJson 和 fromJson 方法，
 * 从而能够方便地在内存和持久存储之间转换数据。
 */
class QBaseEntity : public QObject
{
    Q_OBJECT

    // 使用 Q_PROPERTY 宏定义属性
    Q_PROPERTY(QDateTime createTime READ getCreateTime WRITE setCreateTime)
    Q_PROPERTY(QDateTime updateTime READ getUpdateTime WRITE setUpdateTime)
public:
    enum PropertiesType{
        /**主键属性*/
        PrimaryKeyProperty,
        /**全部属性*/
        AllProperty,
        /**非空属性*/
        UnEmptyProperty,
        /**自定义属性*/
        CustomProperty,
        /**忽略之外属性*/
        IgnoreOutProperty,
    };

    /**
     * @brief 构造一个新的 QBaseEntity 实例。
     *
     * @param parent 指向父对象的指针，如果不需要则可设置为 nullptr。
     */
    explicit QBaseEntity(QObject *parent = nullptr);

    QBaseEntity(const QBaseEntity &other);
    QBaseEntity& operator=(const QBaseEntity &other);

    void copyProperties(const QBaseEntity &other);

    /**
     * @brief 虚拟析构函数，确保派生类能够正确释放资源。
     */
    virtual ~QBaseEntity() {}

    /**
     * @brief 将当前实体的属性转换为 QJsonObject。
     *
     * 子类需要重写此方法以提供具体的属性到 JSON 对象的映射。
     *
     * @return 包含实体属性的 JSON 对象。
     */
    virtual QJsonObject toJsonObject(PropertiesType type = AllProperty,QStringList propertyList = QStringList()) const;

    /**
     * @brief 从给定的 JSON 对象中读取属性并更新实体。
     *
     * 子类需要重写此方法以提供从 JSON 对象到具体属性的映射。
     *
     * @param jsonObject 包含要设置属性值的 JSON 对象。
     */
    virtual void fromJsonObject(const QJsonObject &jsonObject);
    /**
    * @brief 检查当前实体是否为空。
    *
    * 此方法通过遍历所有属性并检查它们是否为空来确定实体是否为空。
    * 属性为空的标准取决于属性的类型：
    * - 字符串：为空字符串 ("")
    * - 整数：为零 (0)
    * - 浮点数：为零 (0.0)
    * - 布尔值：为假 (false)
    * - 列表：为空列表 ([])
    * - 映射：为空映射 ({})
    * - 哈希表：为空哈希表 ({})
    *
    * @return true 如果所有属性都为空，则返回 true；否则返回 false。
    */
    bool isEmpty();
    /**
     * @brief clear 给所有属性置空
     */
    void clear();

    virtual void fromSqlQuery(const QSqlQuery &sql_query);
    /**
    * @brief 设置数据库表名
    * @param tableName 据库表名
    */
    void setTableName(const QString &tableName);
    /**
    * @brief getTableName 获取数据库表名
    * @return
    */
    QString getTableName() const;
    /**
     * @brief 获取主键Key
     * @return
     */
    QString getPrimaryKey() const;
    /**
     * @brief 设置主键Key
     * @param value
     */
    void setPrimaryKey(const QString &value);
    /**
     * @brief 获取忽略键列表
     * @return
     */
    QStringList getIgnoreKeys() const;
    /**
     * @brief 设置忽略键列表
     * @param value
     */
    void setIgnoreKeys(const QStringList &value);

    /**
     * @brief 生成查询 SQL
     * @param 属性选取方式
     * @param 属性集合
     * @return
     */
    virtual QString generateSelectSql(PropertiesType type = UnEmptyProperty,QStringList propertyList = QStringList()) const;

    /**
     * @brief 生成查询总条目 SQL
     * @param 属性选取方式
     * @param 属性集合
     * @return
     */
    virtual QString generateSelectCountSql(PropertiesType type = UnEmptyProperty,QStringList propertyList = QStringList()) const;

    /**
     * @brief 生成插入 SQL
     * @param 属性选取方式
     * @param 属性集合
     * @return
     */
    virtual QString generateInsertSql(PropertiesType type = AllProperty,QStringList propertyList = QStringList()) const;

    /**
     * @brief 生成更新 SQL
     * @param 属性选取方式
     * @param 属性集合
     * @param 参考属性选取方式 （默认主键方式，其他：自定义属性方式）
     * @param 参考属性集合（自定义条件下必须添加属性key）
     * @return
     */
    virtual QString generateUpdateSql(PropertiesType type = UnEmptyProperty,QStringList propertyList = QStringList(),
                                      PropertiesType onType = PrimaryKeyProperty,QStringList onPropertyList = QStringList()) const;


    /**
     * @brief 生成删除 SQL
     * @return
     */
    virtual QString generateDeleteSql(PropertiesType type = UnEmptyProperty,QStringList propertyList = QStringList()) const;

    /**
     * @brief 生成删除主键集合 SQL
     * @return
     */
    virtual QString generateDeleteByKeysSql(QString keyName,QList<QString> values) const;

    /**
     * @brief 生成创建表的 SQL
     * @return
     */
    virtual QString generateCreateTableSql(const QString &driverName = "QMYSQL") const;
    /**
     * @brief 获取唯一键
     * @return
     */
    QStringList getUniqueKeys() const;
    /**
     * @brief 设置唯一键
     * @param value
     */
    void setUniqueKeys(const QStringList &value);
    /**
     * @brief 获取不可为空的键
     * @return
     */
    QStringList getNotNullKeys() const;
    /**
     * @brief 设置不可为空的键
     * @param value
     */
    void setNotNullKeys(const QStringList &value);

    /**
     * @brief 获取所有属性
     * @return
     */
    QVariantMap getAllProperties() const;

    /**
     * @brief 获取非空属性
     * @return
     */
    QVariantMap getUnEmptyProperties() const;

    /**
     * @brief 获取自定义属性
     * @return
     */
    QVariantMap getCustomProperties(QStringList keys) const;

    /**
     * @brief 获取忽略之外属性
     * @param properties
     * @return
     */
    QVariantMap getIgnoreOutProperties(QStringList keys) const;

//private:
    /**
     * @brief 辅助函数，用于将 QVariant 转换为 QJsonValue。
     *
     * @param value 需要转换的 QVariant。
     *
     * @return 转换后的 QJsonValue。
     */
    QJsonValue qvariantToJsonValue(const QVariant &value) const;

    /**
     * @brief 辅助函数，用于将 QJsonValue 转换为 QVariant。
     *
     * @param value 需要转换的 QJsonValue。
     *
     * @return 转换后的 QVariant。
     */
    QVariant qjsonValueToVariant(const QJsonValue &value, int type) const;

    /**
     * @brief 辅助函数，用于将 QSqlValue 转换为 QVariant。
     *
     * @param value 需要转换的 QSqlValue
     *
     * @return 转换后的 QVariant。
     */
    QVariant qSqlValueToVariant(const QVariant &value, int type) const;


    /**
     * @brief 辅助函数，用于判断QVariant是否为空。
     *
     * @param value 需要转换的 QJsonValue。
     *
     * @return 需要判断的 QVariant。
     */
    bool isValueEmpty(const QVariant &value) const;

    QMap<QString, QVariant> getDefaultValueMap() const;
    void setDefaultValueMap(const QMap<QString, QVariant> &value);
    void setDefaultValue(const QString &key,const QVariant &value);
    void clearDefaultValueMap();

    QMap<QString, uint64_t> getPropertiesLengthMap() const;
    void setPropertiesLengthMap(const QMap<QString, uint64_t> &value);
    void setPropertiesLength(const QString &key,const uint64_t length);
    void clearPropertiesLengthMap();

    QDateTime getCreateTime() const;
    void setCreateTime(const QDateTime &value);

    QDateTime getUpdateTime() const;
    void setUpdateTime(const QDateTime &value);

private:
    QString tableName;  /**< 表名 */
    QString primaryKey; /**< 主键 */
    QStringList ignoreKeys; /**< 忽略键 */
    QStringList uniqueKeys; /**< 唯一键 */
    QStringList notNullKeys; /**< 不可为空的键 */
    QMap<QString,QVariant> defaultValueMap; /**< 默认值表 */
    QMap<QString,uint64_t> propertiesLengthMap; /** 属性长度表 */
private:
    QDateTime createTime;
    QDateTime updateTime;
};
//Q_DECLARE_METATYPE(QBaseEntity)
#endif // QBASEENTITY_H
